package cn.jingyuan.swan.gw.web.filter.zuul;

import cn.jingyuan.bee.fastjson.FastJsonUtils;
import cn.jingyuan.bee.utils.BooleanUtils;
import cn.jingyuan.swan.cloud.core.Result;
import cn.jingyuan.swan.cloud.web.AbstractExceptionHandler;
import cn.jingyuan.swan.gw.service.AccessLogService;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * Zuul filter：错误处理
 */
@Slf4j
public class ZuulSendErrorFilter extends ZuulFilter {

    AccessLogService accessLogService;

    public ZuulSendErrorFilter(AccessLogService accessLogService) {
        Assert.notNull(accessLogService, "AccessLogService Can't be null");
        this.accessLogService = accessLogService;
    }

    @Override
    public String filterType() {
        return FilterConstants.ERROR_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_ERROR_FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        if (log.isDebugEnabled()) {
            log.debug(this.getClass().getSimpleName() + " execute before");
        }

        // 代理错误日志记录
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();

        Throwable throwable = ctx.getThrowable();
        Exception ex = new Exception(throwable);

        boolean rateLimitFlag = false;
        Object rateLimitExceeded = ctx.get("rateLimitExceeded");
        if (null != rateLimitExceeded) {
            rateLimitFlag = BooleanUtils.toBoolean(rateLimitExceeded.toString());
        }

        if (rateLimitFlag) {
            ex = new Exception(HttpStatus.TOO_MANY_REQUESTS.name());
        }

        try {
            // FIXME 记录日志只存储
            accessLogService.sendLog(request, response, ex);
        } catch (Exception e) {
            log.error("记录日志错误", e);
        }

        Result result = AbstractExceptionHandler.resolveEx(ex);

        try {
            Charset charset = StandardCharsets.UTF_8;

            response.setStatus(result.getHttpStatus());
            response.setCharacterEncoding(charset.name());
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);

            String body = FastJsonUtils.json(result);

            ServletOutputStream out = response.getOutputStream();
            out.write(body.getBytes(charset));
            out.flush();
        } catch (IOException e) {
            // ignore
        }

        if (log.isDebugEnabled()) {
            log.debug(this.getClass().getSimpleName() + " execute end");
        }

        return null;
    }

}
